package com.archgeek.java.conc.lock;

import java.util.ArrayList;
import java.util.List;

/**
 *
 * 同步等待节点类
 *
 * @author pizhihui
 * @date 2023-04-20 15:28
 */
public class AqsNode {

    //  标记一个节点处于共享模式下的等待
    static final AqsNode SHARED = new AqsNode();
    // 标记一个节点处于独占模式下的等待
    static final AqsNode EXCLUSIVE = null;

    /**
     * 四种状态
     * 1:  取消
     * -1: 唤醒
     * -2: 条件等待
     * -3: 传播
     */
    static final int CANCELLED =  1;
    static final int SIGNAL    = -1;
    static final int CONDITION = -2;
    static final int PROPAGATE = -3;

    // 等待状态，初始值为0，其他可选值是上面的4个值
    volatile int waitStatus;

    // 当前节点前驱节点的引用
    volatile AqsNode prev;

    // 当前节点后继节点的引用
    volatile AqsNode next;

    // 当前节点持有的线程，可能是阻塞中等待唤醒的线程
    volatile Thread thread;


    // 下一个等待节点
    AqsNode nextWaiter;


    final boolean isShared() {
        return nextWaiter == SHARED;
    }

    // 获取当前节点的前驱节点，确保前驱节点必须存在，否则抛出NPE
    final AqsNode predecessor() throws NullPointerException {
        AqsNode p = prev;
        if (p == null)
            throw new NullPointerException();
        else
            return p;
    }

    AqsNode() {    // Used to establish initial head or SHARED marker
    }

    AqsNode(AqsNode nextWaiter) {
        this.nextWaiter = nextWaiter;
        // thread.set(this, Thread.currentThread());
    }

    AqsNode(Thread thread, AqsNode mode) {     // Used by addWaiter
        this.nextWaiter = mode;
        this.thread = thread;
    }

    AqsNode(Thread thread, int waitStatus) { // Used by Condition
        this.waitStatus = waitStatus;
        this.thread = thread;
    }

    public static void main(String[] args) throws Exception {
        AqsNode head = new AqsNode();
        AqsNode next = new AqsNode(AqsNode.EXCLUSIVE);
        head.next = next;
        next.prev = head;
        AqsNode tail = new AqsNode(AqsNode.EXCLUSIVE);
        next.next = tail;
        tail.prev = next;
        List<Thread> threads = new ArrayList<>();
        for (AqsNode node = head; node != null; node = node.next) {
            threads.add(node.thread);
        }
        System.out.println(threads);
    }
}
